package com.wsz.security_fx.config.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.wsz.security_fx.config.exception.CodeException;
import com.wsz.security_fx.utils.JwtUtils;
import com.wsz.security_fx.pojo.User;
import com.wsz.security_fx.utils.RedisOperator;
import lombok.Data;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.util.StringUtils;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

@Data
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    private RedisOperator redisOperator;

    public static final String SPRING_SECURITY_FORM_CODE_KEY = "username";
    private String codeParameter = "code";

    public CustomAuthenticationFilter(RedisOperator redisOperator) {
        this.redisOperator = redisOperator;
    }

    //尝试认证
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        if (!request.getMethod().equals("POST")) {
                throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
            }
            if("application/json".equals(request.getContentType())){
                try {
                    Map<String,String> data = new ObjectMapper().readValue(request.getInputStream(),Map.class);
                    String username = data.get(getUsernameParameter());
                    String password = data.get(getPasswordParameter());
                    String code = data.get(getCodeParameter());

                    String redisCode = redisOperator.get(getCodeParameter());

                    if(!StringUtils.isEmpty(code) && !StringUtils.isEmpty(redisCode) && code.equals(redisCode)){
                        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username,password);
                        System.out.println("username:"+username);
                        System.out.println("password:"+password);
                        this.setDetails(request, authRequest);
                        return this.getAuthenticationManager().authenticate(authRequest);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            throw new CodeException("验证码错误");
    }

    //认证成功
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) throws IOException, ServletException {

        User user = (User) authentication.getPrincipal();
        String access_toke = JwtUtils.createAccessToken(user.getUsername(),
                request.getRequestURI(),
                user.getRoles().stream().map(role -> role.getName()).collect(Collectors.toList()));

        String refresh_token = JwtUtils.createRefreshToken(user.getUsername(), request.getRequestURI());

        Map<String,Object> data = new HashMap<>();
        data.put("access_token",access_toke);
        data.put("refresh_token",refresh_token);

        response.setContentType("application/json;UTF-8");
        new ObjectMapper().writeValue(response.getOutputStream(),data);
    }

    //认证失败
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        Map<String,Object> data = new HashMap<>();
        data.put("msg","认证失败");
        data.put("status",201);
        response.setContentType("application/json;UTF-8");
        new ObjectMapper().writeValue(response.getOutputStream(),data);
    }
}
